﻿namespace Common.ChartDrawing
{
    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;
    using System.Windows.Shapes;

    using Common.Helpers;
    using Common.Protocol;

    public class ElementsInitializer
    {
        private CanvasElements elements;

        private ProtocolInterval interval;

        public ElementsInitializer(ProtocolInterval interval)
        {
            this.interval = interval;
            this.elements = new CanvasElements();
        }

        public CanvasElements Initialize()
        {
            this.elements = new CanvasElements();
            this.InitGridVerticals();
            this.InitEmptyIntervalsGridHorizontals();
            this.InitCharts();
            this.InitRedLine();

            return this.elements;
        }

        public void SetRedLinePosition(double y)
        {
            if (this.interval != null)
            {
                this.elements.RedLine.Y1 = this.elements.RedLine.Y2 = y;

                if (this.elements.RedLine.Y1 <= Constants.Height - 15)
                {
                    this.elements.CurrentDateLabel.Margin = new Thickness(
                        Constants.Width - 65, this.elements.RedLine.Y1 + 1, 0, 0);
                    this.elements.CurrentTimeLabel.Margin = new Thickness(1, this.elements.RedLine.Y1 + 1, 0, 0);
                }
                else
                {
                    this.elements.CurrentDateLabel.Margin = new Thickness(
                        Constants.Width - 65, this.elements.RedLine.Y1 - 15, 0, 0);
                    this.elements.CurrentTimeLabel.Margin = new Thickness(1, this.elements.RedLine.Y1 - 15, 0, 0);
                }
            }
        }

        private void InitGridVerticals()
        {
            for (int i = 0; i <= Constants.UsefulWidth; i += Constants.HorizontalIndent)
            {
                this.elements.GridVerticals.Add(PrimitivesDrawer.GridVertical(i + Constants.FieldsWidth));
            }
        }

        private void InitEmptyIntervalsGridHorizontals()
        {
            double y = Constants.Height;

            // before start
            while (y > Constants.StartCharts + Constants.VerticalIndent)
            {
                y -= Constants.VerticalIndent;
                this.elements.GridHorizontals.Add(PrimitivesDrawer.GridHorizontal(y));
            }

            // after end
            y = Constants.EndCharts;
            while (y >= 0)
            {
                this.elements.GridHorizontals.Add(PrimitivesDrawer.GridHorizontal(y));
                y -= Constants.VerticalIndent;
            }
        }

        private void InitCharts()
        {
            double blockStart = Constants.StartCharts;

            foreach (var block in this.interval.Blocks)
            {
                ChartScale scale = new ChartScale();
                scale.StepMilliseconds = this.interval.StepMilliseconds;
                scale.TotalMilliseconds = (int)this.interval.TotalMilliseconds;
                double blockHeight = (block.TotalMilliseconds * 1.0 / this.interval.TotalMilliseconds)
                                     * Constants.Height;

                this.InitHorizontalsAndLabels(block.Start, block.End, scale, blockStart, blockHeight);

                if (block.EndLine == 1)
                {
                    this.elements.SolidEndOfBlockLines.Add(PrimitivesDrawer.SolidEndOfBlockLine(blockStart));
                }
                else
                {
                    this.elements.EndOfBlockLines.Add(PrimitivesDrawer.EndOfBlockLine(blockStart));
                }

                //initializing channel charts
                foreach (var channel in block.Channels)
                {
                    //if (channel.Id == "A3")
                    //{
                        double periodsByPixel = channel.Values.Count / blockHeight;
                        if (periodsByPixel < 2)
                        {
                            ChartInitializer.InitChannelChart(
                                blockStart, blockHeight, channel, this.elements, block.Start, block.End);
                        }
                        else
                        {
                            ChartInitializer.InitCompressedChannelChart(
                                blockStart, blockHeight, channel, this.elements, block.Start, block.End);
                        }
                    //}
                }

                blockStart -= blockHeight;
                if (blockStart >= 1)
                {
                    if (block.EndLine == 1)
                    {
                        this.elements.SolidEndOfBlockLines.Add(PrimitivesDrawer.SolidEndOfBlockLine(blockStart));
                    }
                    else
                    {
                        this.elements.EndOfBlockLines.Add(PrimitivesDrawer.EndOfBlockLine(blockStart));
                    }
                }
            }
        }

        private void InitHorizontalsAndLabels(DateTime startTime, DateTime endTime,
            ChartScale scale, double blockStart, double blockHeight)
        {
            DateTime labelTime = TimeCounter.FindCoolTime(startTime, scale);
            double labelPosition = 0;

            if (endTime > labelTime)
            {
                labelPosition = blockStart - (labelTime - startTime).TotalMilliseconds / Constants.MillisecondsByPixel;
                for (double j = labelPosition; j > blockStart - blockHeight; j -= Constants.VerticalIndent)
                {
                    this.elements.GridHorizontals.Add(PrimitivesDrawer.GridHorizontal(j));
                    this.elements.DateLabels.Add(PrimitivesDrawer.DateLabel(j, labelTime));
                    this.elements.TimeLabels.Add(PrimitivesDrawer.TimeLabel(j, labelTime));
                    labelTime = labelTime.AddMilliseconds(scale.StepMilliseconds);
                }
            }
        }

        private void InitRedLine()
        {
            this.elements.RedLine = new Line();
            this.elements.RedLine.Stroke = Brushes.Red;
            this.elements.RedLine.StrokeThickness = 2;
            this.elements.RedLine.X1 = 0;
            this.elements.RedLine.X2 = Constants.Width;
            this.elements.RedLine.Y2 = this.elements.RedLine.Y1 = Constants.Height / 2f;

            this.elements.CurrentTimeLabel = new TextBlock();
            this.elements.CurrentDateLabel = new TextBlock();
            this.elements.CurrentTimeLabel.FontSize = this.elements.CurrentDateLabel.FontSize = 12;
            this.elements.CurrentTimeLabel.Foreground = this.elements.CurrentDateLabel.Foreground = Brushes.Red;

            this.elements.CurrentTimeLabel.Text = Constants.CurrentTime.ToLongTimeString() + "." + Constants.CurrentTime.Millisecond / 100;
            this.elements.CurrentDateLabel.Text = Constants.CurrentTime.ToShortDateString();

            this.SetRedLinePosition((int)Constants.Height / 2);

            Canvas.SetZIndex(this.elements.RedLine, 5);
            Canvas.SetZIndex(this.elements.CurrentTimeLabel, 5);
            Canvas.SetZIndex(this.elements.CurrentDateLabel, 5);
        }
    }
}